// **************************************************************
// Com ++ Framework by the C++ World
// Please report defects: mailto:compp@cplusplusworld.com
// Please visit: http://www.cplusplusworld.com/socketlibrary.html
// **************************************************************

#include <arpa/inet.h>
#include "ComPlusPlus/Comm.h"
#include "ComPlusPlus/AClnt.h"

#include "SysPlusPlus/Tools.h"
#include "SysPlusPlus/Logger.h"

#include "Sig.h"

// #define SPECIAL_DEBUG 1
compp::AClnt::AClnt( const std::string & IPAddr, const int port ) {

  S.Connect ( IPAddr, port);
  S.AttachFD();

}

bool compp::AClnt::disConnect( ) {

  S.Close();
  return true;
}

bool compp::AClnt::Connect( const std::string & IPAddr, const int port ) {

  S.Connect ( IPAddr, port);
  S.AttachFD();

  return true;
}

compp::AClnt::AClnt(  ) {


}

compp::AClnt::~AClnt( ) {



}


std::string compp::AClnt:: requestTransaction (  const std::string & request, const bool cyphered ) {
  syspp::Logger *Log = syspp::Logger::Instance();

  long Sec = htonl ( _COMM_SEC  );
  long Cyph = htonl ( _COMM_CYPH );
  int Len = htonl ( (int)request.size() + 12 );
  int SIGNATURE= 123, i;
  char c[sizeof (int) ]; // Temporary
  std::string R = "";
  int senderport;
  std::string retval, senderhost;
  bool responsecorrect;
  std::string response;
  
  // SEC
  try {
    if ( cyphered ) {
      memcpy ( (void*) c, (void*) &Cyph, sizeof (Cyph));
      Log->Debug ("AClnt cyphered request." );

    } else {
      memcpy ( (void*) c, (void*) &Sec, sizeof (Sec));
      Log->Debug ("AClnt uncyphered request." );
    }

    R.append ( c, sizeof ( Len ) );

    // ID
    memcpy ( (void*) c, (void*) &Len, sizeof (Len));
    R.append ( c, sizeof ( Len ) );

    // SIGNATURE
    memcpy ( (void*) c, (void*) &SIGNATURE, sizeof (SIGNATURE));
    R.append ( c, sizeof ( SIGNATURE ) );

    if ( cyphered ) {
      std::string cs = request;
      syspp::Tools::Enc (cs);
#ifdef SPECIAL_DEBUG    
      std::cout << request  <<  cs << "\n" ;
#endif
      R.append ( cs );
    } else {
      R.append ( request );
#ifdef SPECIAL_DEBUG    
      std::cout << request << "\n" ;
#endif
    }

#ifdef SPECIAL_DEBUG    
    std::cout << ":" << R << "\n" ;
    for ( int u = 0; u < R.size(); ++ u ) 
      printf ("%d ", R[u] );
    std::cout  << "\n";
#endif

    if ( S.Write ( R) <= 0 ) {
      Log->Error ("Server does not accept command." );
      throw syspp::ComException ( "Server does not accept comands." )  ;    
    }

    do {

      if ( false == S.PollRcv ( 1000000 ) ) {
	Log->Error ("Server does not respond." );
	throw syspp::ComException ( "Server does not respond (7)." )  ;    
      }
      
      if ( S.Read ( retval, senderhost, senderport ) <= 0 ) {
	Log->Error ("Server does not respond (2)." );
	throw syspp::ComException ( "Server does not respond (2)." )  ;    
      }

      if ( retval.size() < 12 ) {
	Log->Error ("Server does not respond (3)." );
	throw syspp::ComException ( "Server does not respond (3)." )  ;          
      }

      retval.copy ( (char *) &i, 4, 0 );
    
      if ( cyphered ) {
	if ( i != Cyph ) {
	  Log->Error ("Server does not respond (4)." );
	  throw syspp::ComException ( "Server does not respond (4)." )  ;          
	}
      } else {
	if ( i != Sec ) {
	  Log->Error ("Server does not respond (5)." );
	  throw syspp::ComException ( "Server does not respond (5)." )  ;          
	}
      }

      retval.copy ( (char *) &i, 4, 4 );
      i = ntohl ( i );

      if ( i != (int) ( retval.size() ) ) {
	Log->Error ("Server does not respond (6)." );
	throw syspp::ComException ( "Server does not respond (6)." )  ;          
    }


      retval.copy ( (char *) &i, 4, 8 );
      if ( i == SIGNATURE ) {
	responsecorrect = true;
      }	else {
	responsecorrect = false;
      }
	  
    } while ( responsecorrect == false );

    response = retval.substr (  12, retval.size() -12  );
    
    if ( cyphered ) {
#ifdef SPECIAL_DEBUG
      std::cout << "CYPH res " << response << "\n" ;
#endif
      syspp::Tools::Dec (response);
#ifdef SPECIAL_DEBUG
      std::cout << "CYPH res(2) " << response << "\n" ;
#endif
    } else {
#ifdef SPECIAL_DEBUG
      std::cout << "NORM res " << response << "\n" ;
#endif
    }

  } catch ( syspp::ComException &e ) {
    std::string s = "Server Communication Exception : (" ;
    s += e.what () ;
    s += ")";
    Log->Error ( s.c_str() );
    throw  syspp::ComException ( s.c_str() )  ;    
  } catch ( ... ) {
    std::string s = "Server Communication Exception : (General)" ;
    Log->Error ( s.c_str() );
    throw syspp::ComException ( s.c_str()  ) ;
  }

  Log->Debug ("AClnt response OK." );
  return response;
}
